package com.goldman.oss.common.platform.impl;

import com.goldman.oss.common.internal.pojo.*;
import com.goldman.oss.common.platform.FileStorage;
import com.goldman.oss.common.utils.PathUtils;
import com.obs.services.ObsClient;
import com.obs.services.model.*;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.BeanUtils;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.function.Consumer;

/**
 * 华为云 OBS
 *
 * @author fdr
 */
@Data
@Slf4j
public class HuaweiObsFileStorage implements FileStorage {
    private String businessCode;
    private String accessKey;
    private String secretKey;
    private String endPoint;
    private String bucketName;
    private String domain;
    private String basePath;
    private volatile ObsClient client;

    private Long defaultExpirationInSeconds;

    public ObsClient getClient() {
        if (client == null) {
            synchronized (this) {
                if (client == null) {
                    client = new ObsClient(accessKey, secretKey, endPoint);
                }
            }
        }
        return client;
    }


    @Override
    public void close() {
        IOUtils.closeQuietly(client);
    }

    @Override
    public UploadFileInfo store(MultipartFileWrapper fileWrapper) {
        try {
            return store(fileWrapper, fileWrapper.getMultipartFile().getInputStream());
        } catch (IOException e) {
            log.error("上传文件到obs异常：" + e.getMessage(), e);
            throw new RuntimeException(e);
        }
    }

    @Override
    public UploadFileInfo store(CommonFileWrapper commonFileWrapper) {
        try {
            return store(commonFileWrapper, new FileInputStream(commonFileWrapper.getFile()));
        } catch (FileNotFoundException e) {
            log.error("上传文件到obs异常：" + e.getMessage(), e);
            throw new RuntimeException(e);
        }
    }

    private UploadFileInfo store(FileWrapper fileWrapper, InputStream in) {
        log.info("开始上传文件到obs:{}", fileWrapper.getFilename());
        try {
            String objectKey = getObjectKey(fileWrapper);
            UploadFileInfo uploadFileInfo = new UploadFileInfo();
            BeanUtils.copyProperties(fileWrapper, uploadFileInfo);
            uploadFileInfo.setBasePath(basePath);
            uploadFileInfo.setObjectKey(objectKey);
            uploadFileInfo.setUrl(PathUtils.addFileSeparatorIfNot(domain) + objectKey);
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentLength(uploadFileInfo.getSize());

            ObsClient obsClient = getClient();
            obsClient.putObject(bucketName, objectKey, in, metadata);
            if (fileWrapper.isPublicRead()) {
                obsClient.setObjectAcl(bucketName, objectKey, AccessControlList.REST_CANNED_PUBLIC_READ);
            }
            return uploadFileInfo;
        } catch (Exception e) {
            log.error("上传文件到obs异常：" + e.getMessage(), e);
            throw new RuntimeException(e);
        }
    }


    private String getObjectKey(FileWrapper fileWrapper) {
        String objectKey = PathUtils.addFileSeparatorIfNot(basePath) +
                PathUtils.addFileSeparatorIfNot(fileWrapper.getPath()) +
                fileWrapper.getFilename();
        return PathUtils.removeFirstFileSeparatorIfExists(objectKey);
    }


    @Override
    public String generateTemporaryUrl(DownloadFileInfo downloadFileInfo) {
        log.info("开始从obs获取临时URL:{}", downloadFileInfo.getObjectKey());
        try {
            Long expireInSeconds = downloadFileInfo.getExpirationTimeInSeconds() != null ?
                    downloadFileInfo.getExpirationTimeInSeconds() : defaultExpirationInSeconds;
            TemporarySignatureRequest request = new TemporarySignatureRequest(HttpMethodEnum.GET, expireInSeconds);
            request.setBucketName(bucketName);
            request.setObjectKey(downloadFileInfo.getObjectKey());
            TemporarySignatureResponse response = getClient().createTemporarySignature(request);
            return response.getSignedUrl();
        } catch (Exception e) {
            log.error("genObSSignedUrl error: ", e);
            throw new RuntimeException(e);
        }
    }

    @Override
    public String generatePublicUrl(String objectKey) {
        return String.format("https://%s.%s/%s", bucketName, endPoint, objectKey);
    }

    @Override
    public void download(DownloadFileInfo downloadFileInfo, Consumer<InputStream> consumer) {
        ObsObject object = getClient().getObject(bucketName, downloadFileInfo.getObjectKey());
        try (InputStream in = object.getObjectContent()) {
            consumer.accept(in);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public InputStream download(DownloadFileInfo downloadFileInfo) {
        ObsObject object = getClient().getObject(bucketName, downloadFileInfo.getObjectKey());
        return object.getObjectContent();
    }
}
